package org.openfdtd.core3d.behaviors;

import com.sun.j3d.utils.behaviors.mouse.MouseBehavior;
import java.awt.AWTEvent;
import java.awt.event.MouseEvent;
import java.util.Enumeration;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.WakeupCriterion;
import javax.media.j3d.WakeupOnAWTEvent;
import javax.media.j3d.WakeupOnBehaviorPost;
import javax.vecmath.Vector3d;

/**
 *
 * @author Dorian C. Langbeck
 */
public class MouseTranslate extends MouseBehavior {
    private double x_factor = .002;
    private double y_factor = .002;
    private Vector3d translation = new Vector3d();


    public MouseTranslate(TransformGroup transformGroup) {
        super(transformGroup);
    }

    @Override
    public void initialize() {
        super.initialize();
        if ((flags & INVERT_INPUT) == INVERT_INPUT) {
            invert = true;
            x_factor *= -1;
            y_factor *= -1;
        }
    }

    public double getXFactor() {
        return x_factor;
    }

    public double getYFactor() {
        return y_factor;
    }

    public void setFactor( double factor) {
        x_factor = y_factor = factor;
    }

    public void setFactor( double xFactor, double yFactor) {
        x_factor = xFactor;
        y_factor = yFactor;
    }

    public void processStimulus (Enumeration criteria) {
        WakeupCriterion wakeup;
        AWTEvent[] events;
        MouseEvent evt;

        while (criteria.hasMoreElements()) {
            wakeup = (WakeupCriterion) criteria.nextElement();

            if (wakeup instanceof WakeupOnAWTEvent) {
                events = ((WakeupOnAWTEvent)wakeup).getAWTEvent();
                if (events.length > 0) {
                    evt = (MouseEvent) events[events.length-1];
                    doProcess(evt);
                }
            } else if (wakeup instanceof WakeupOnBehaviorPost) {
                while (true) {
                    synchronized (mouseq) {
                        if (mouseq.isEmpty()) break;
                        evt = (MouseEvent) mouseq.remove(0);
                        while ((evt.getID() == MouseEvent.MOUSE_DRAGGED) && !mouseq.isEmpty() && (((MouseEvent)mouseq.get(0)).getID() == MouseEvent.MOUSE_DRAGGED))
                            evt = (MouseEvent) mouseq.remove(0);
                    }
                    doProcess(evt);
                }
            }

        }
        wakeupOn(mouseCriterion);
    }

    private void doProcess(MouseEvent evt) {
        int id;
        int dx, dy;

        processMouseEvent(evt);
        if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) || ((wakeUp)&&((flags & MANUAL_WAKEUP) != 0))) {
            id = evt.getID();
            if ((id == MouseEvent.MOUSE_DRAGGED) && evt.isAltDown() && !evt.isMetaDown() && evt.isShiftDown()) {
                x = evt.getX();
                y = evt.getY();

                dx = x - x_last;
                dy = y - y_last;

                if ((!reset) && ((Math.abs(dy) < 50) && (Math.abs(dx) < 50))) {
                    transformGroup.getTransform(currXform);
                    translation.x = dx * x_factor;
                    translation.y = -dy * y_factor;
                    transformX.set(translation);
                    if (invert)
                        currXform.mul(currXform, transformX);
                    else
                        currXform.mul(transformX, currXform);

                    transformGroup.setTransform(currXform);

                } else
                    reset = false;
                
                x_last = x;
                y_last = y;
            } else if (id == MouseEvent.MOUSE_PRESSED) {
                x_last = evt.getX();
                y_last = evt.getY();
            }
        }
    }
}
